{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "9CwaNZBFSlqw"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import tensorflow as tf\n",
        "import tensorflow.keras as K\n",
        "import matplotlib.pyplot as plt\n",
        "from tensorflow.keras import regularizers"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "Zl7O8xFmSlqz"
      },
      "outputs": [],
      "source": [
        "np.random.seed(11)\n",
        "tf.random.set_seed(11)\n",
        "batch_size = 256\n",
        "max_epochs = 50\n",
        "learning_rate = 1e-3\n",
        "momentum = 8e-1\n",
        "hidden_dim = 128\n",
        "original_dim = 784"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "I-X29AlGSlq2",
        "outputId": "2cb342e2-a220-4096-e374-9991236fcf63"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz\n",
            "11493376/11490434 [==============================] - 0s 0us/step\n",
            "11501568/11490434 [==============================] - 0s 0us/step\n"
          ]
        }
      ],
      "source": [
        "(x_train, _), (x_test, _) = K.datasets.mnist.load_data()\n",
        "\n",
        "x_train = x_train / 255.\n",
        "x_test = x_test / 255.\n",
        "\n",
        "x_train = x_train.astype(np.float32)\n",
        "x_test = x_test.astype(np.float32)\n",
        "\n",
        "x_train = np.reshape(x_train, (x_train.shape[0], 784))\n",
        "x_test = np.reshape(x_test, (x_test.shape[0], 784))\n",
        "\n",
        "training_dataset = tf.data.Dataset.from_tensor_slices(x_train).batch(batch_size)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "sIG3LgINSlq4"
      },
      "outputs": [],
      "source": [
        "\n",
        "class SparseEncoder(K.layers.Layer):\n",
        "    def __init__(self, hidden_dim):\n",
        "        super(SparseEncoder, self).__init__()\n",
        "        self.hidden_layer = K.layers.Dense(units=hidden_dim, \n",
        "                    activation=tf.nn.relu, activity_regularizer=regularizers.l1(10e-5))\n",
        "        \n",
        "    \n",
        "    def call(self, input_features):\n",
        "        activation = self.hidden_layer(input_features)\n",
        "        return activation"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "nvPRVIpjSlq5"
      },
      "outputs": [],
      "source": [
        "\n",
        "class SparseDecoder(K.layers.Layer):\n",
        "    def __init__(self, hidden_dim, original_dim):\n",
        "        super(SparseDecoder, self).__init__()\n",
        "        self.output_layer = K.layers.Dense(units=original_dim, activation=tf.nn.relu)\n",
        "  \n",
        "    def call(self, encoded):\n",
        "        activation = self.output_layer(encoded)\n",
        "        return activation "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "id": "lARDVsiBSlq7"
      },
      "outputs": [],
      "source": [
        "class SparseAutoencoder(K.Model):\n",
        "    def __init__(self, hidden_dim, original_dim):\n",
        "        super(SparseAutoencoder, self).__init__()\n",
        "        self.loss = []\n",
        "        self.encoder = SparseEncoder(hidden_dim=hidden_dim)\n",
        "        self.decoder = SparseDecoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
        "\n",
        "    def call(self, input_features):\n",
        "        encoded = self.encoder(input_features)\n",
        "        reconstructed = self.decoder(encoded)\n",
        "        return reconstructed"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "id": "CQ5O6Xz1Slq8"
      },
      "outputs": [],
      "source": [
        "autoencoder = SparseAutoencoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
        "opt = tf.optimizers.SGD(learning_rate=learning_rate, momentum=momentum)\n",
        "\n",
        "def loss(preds, real):\n",
        "    return tf.reduce_mean(tf.square(tf.subtract(preds, real))) \n",
        "\n",
        "def train(loss, model, opt, original):\n",
        "    with tf.GradientTape() as tape:\n",
        "        preds = model(original)\n",
        "        reconstruction_error = loss(preds, original)\n",
        "    gradients = tape.gradient(reconstruction_error, model.trainable_variables)\n",
        "    gradient_variables = zip(gradients, model.trainable_variables)\n",
        "    opt.apply_gradients(gradient_variables)\n",
        "  \n",
        "    return reconstruction_error"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "qERcmX-gSlq-"
      },
      "outputs": [],
      "source": [
        "def train_loop(model, opt, loss, dataset, epochs=20):\n",
        "    for epoch in range(epochs):\n",
        "        epoch_loss = 0\n",
        "        for step, batch_features in enumerate(dataset):\n",
        "            loss_values = train(loss, model, opt, batch_features)\n",
        "            epoch_loss += loss_values\n",
        "        model.loss.append(epoch_loss)\n",
        "        print('Epoch {}/{}. Loss: {}'.format(epoch + 1, epochs, epoch_loss.numpy()))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "H1S72XNYSlq_",
        "outputId": "a371ae30-0758-432a-feca-edcae064a2e2"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Epoch 1/50. Loss: 5.1587958335876465\n",
            "Epoch 2/50. Loss: 3.0754802227020264\n",
            "Epoch 3/50. Loss: 2.9578378200531006\n",
            "Epoch 4/50. Loss: 2.902768135070801\n",
            "Epoch 5/50. Loss: 2.8737621307373047\n",
            "Epoch 6/50. Loss: 2.868150234222412\n",
            "Epoch 7/50. Loss: 2.8591814041137695\n",
            "Epoch 8/50. Loss: 2.841956615447998\n",
            "Epoch 9/50. Loss: 2.8421523571014404\n",
            "Epoch 10/50. Loss: 2.825453281402588\n",
            "Epoch 11/50. Loss: 2.824692487716675\n",
            "Epoch 12/50. Loss: 2.816127300262451\n",
            "Epoch 13/50. Loss: 2.7946760654449463\n",
            "Epoch 14/50. Loss: 2.793262243270874\n",
            "Epoch 15/50. Loss: 2.78263258934021\n",
            "Epoch 16/50. Loss: 2.7990469932556152\n",
            "Epoch 17/50. Loss: 2.7821526527404785\n",
            "Epoch 18/50. Loss: 2.766003131866455\n",
            "Epoch 19/50. Loss: 2.78568434715271\n",
            "Epoch 20/50. Loss: 2.7810020446777344\n",
            "Epoch 21/50. Loss: 2.784510612487793\n",
            "Epoch 22/50. Loss: 2.7613911628723145\n",
            "Epoch 23/50. Loss: 2.782315731048584\n",
            "Epoch 24/50. Loss: 2.7735226154327393\n",
            "Epoch 25/50. Loss: 2.79789662361145\n",
            "Epoch 26/50. Loss: 2.762590169906616\n",
            "Epoch 27/50. Loss: 2.8043038845062256\n",
            "Epoch 28/50. Loss: 2.7781097888946533\n",
            "Epoch 29/50. Loss: 2.7538812160491943\n",
            "Epoch 30/50. Loss: 2.7984564304351807\n",
            "Epoch 31/50. Loss: 2.7639100551605225\n",
            "Epoch 32/50. Loss: 2.770054578781128\n",
            "Epoch 33/50. Loss: 2.7842397689819336\n",
            "Epoch 34/50. Loss: 2.796147584915161\n",
            "Epoch 35/50. Loss: 2.7590126991271973\n",
            "Epoch 36/50. Loss: 2.770280599594116\n",
            "Epoch 37/50. Loss: 2.75842022895813\n",
            "Epoch 38/50. Loss: 2.7988779544830322\n",
            "Epoch 39/50. Loss: 2.7554867267608643\n",
            "Epoch 40/50. Loss: 2.7893588542938232\n",
            "Epoch 41/50. Loss: 2.7740509510040283\n",
            "Epoch 42/50. Loss: 2.782309055328369\n",
            "Epoch 43/50. Loss: 2.7725584506988525\n",
            "Epoch 44/50. Loss: 2.781611680984497\n",
            "Epoch 45/50. Loss: 2.796462059020996\n",
            "Epoch 46/50. Loss: 2.765658378601074\n",
            "Epoch 47/50. Loss: 2.751145601272583\n",
            "Epoch 48/50. Loss: 2.777538537979126\n",
            "Epoch 49/50. Loss: 2.7776002883911133\n",
            "Epoch 50/50. Loss: 2.7515852451324463\n"
          ]
        }
      ],
      "source": [
        "model = SparseAutoencoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
        "opt = tf.keras.optimizers.Adam(learning_rate=1e-2)\n",
        "\n",
        "train_loop(model, opt, loss, training_dataset, epochs=max_epochs)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 279
        },
        "id": "C3wDXcIrSlrC",
        "outputId": "c1645514-b7ab-4a53-c624-04c558d39fda"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          }
        }
      ],
      "source": [
        "\n",
        "plt.plot(range(max_epochs), model.loss)\n",
        "plt.xlabel('Epochs')\n",
        "plt.ylabel('Loss')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 248
        },
        "id": "Eg8PDQYoSlrD",
        "outputId": "d2c53cf5-9b93-4fa7-e983-3ce53563c626"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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vvvuu25s1qxZGn/66acaT58+3c378ccf474+kmfLKYj4c8zea4Z/E8nq1KmTxj/99JMbmz9/vsYTJkxwY/ZvbseOHcX63clgpw0AAAAAAEAE8dAGAAAAAAAggnhoAwAAAAAAEEFZrWljW3yLiBx55JEaz507140ddthhGifKKz766KM1/vbbbzWO16IvFpvHtnbtWo1tO+vQ0qVL3XG+1rSxbP2K4rruuus0bt68edx5Npc01jGi6/rrr9c4/JvhPEqPt956S2Pbkru4bGvTLVu2uLGGDRtqbNvOTpkyxc0rU6ZMideR68J8btu2edGiRRr/4x//yNiaTjvttIz9LuzpiCOOcMft2rWLO9fe27z99ttpW1OuqFWrljs+88wz48698MILNbb3jelm69iMHTs27rywpk1YDxIi1157rca2hXuywjptJ598ssZh23Bb/yadNTByVaI6M61bt9bYtnoOTZ48WWP7vXLx4sVuXoMGDTS2tUxFUlMHEHuyzwMuv/xyjcNzrEqVKjF/fvny5e74448/1vibb75xY/Y7iK2t2LFjRzfPXhN69+7txmbMmKGxbRueauy0AQAAAAAAiCAe2gAAAAAAAERQVtOj3n///YTHVtiq7Rdhu9E2bdpobLc5dejQIel1bdu2TeMFCxZoHKZs2a1Sdms6SuaUU07R2LbO3Hfffd28NWvWaPx///d/bmzr1q1pWh1KqlGjRu64ffv2GtvzTYTWiKlywgknuONDDz1UY7u9N9mtvuH2T7s92bbOFBE58cQTNU7Ujviyyy7TeNiwYUmtI9/cdNNN7thuEbdb8cMUtVSzn33h3xbbxTMrUcpOKEwjQGL/+te/3PF5552nsb2/FBF56aWXMrKmUJcuXTSuXbu2G3vyySc1fvbZZzO1pFLDpu6KiAwZMiTmvC+//NIdr169WuMePXrEff2qVatqbFOvRESee+45jVetWrX3xea58P7/+eef19imQ4n49OBEKYNWmBJlheUvkHqPPPKIO7ZpbYnad9vnBjNnztT4L3/5i5tnv9eHjj32WI3tfejjjz/u5tnnC/YaICLy4IMPavzKK69onOpUWXbaAAAAAAAARBAPbQAAAAAAACIoq+lRqbBx40Z3PG7cuJjzEqVeJWK3HoepWHYr1vDhw4v1+tiTTZcJt0Ra9t98/PjxaV0TUidMp7Ay2XUj19k0tBdffNGNJdpuatluXnbL59///nc3L1E6on2N3//+9xrXrFnTzbvzzjs1rlChghv7z3/+o/HOnTv3tuyc0r9/f43DjgULFy7UOJOd1myaW5gO9eGHH2r83XffZWpJeev444+POxZ2pUmUnog9FRYWumP7t75ixQo3ls4OQBUrVnTHduv/H/7wB43D9V5wwQVpW1MusOkOIiKVK1fW2HabCe9Z7OfTOeeco3GYktG0aVON69Sp48ZGjhypca9evTTesGFDUmvPB/vvv7/GYQkEW0Zh3bp1buzuu+/WmFIJ0RHe19muTRdddJEbKygo0Nh+LwhT5++66y6Ni1tOoUaNGhrbLqa33HKLm2fLtISplZnCThsAAAAAAIAI4qENAAAAAABABPHQBgAAAAAAIIJKfU2bdKhVq5bGDz30kMb77OOfcdl21OShFt/rr7/ujk866aSY855++ml3HLa/RelwxBFHxB2zdU1QMmXL/np5T7aGTVgbauDAgRqHeePJsjVt/vnPf2p8zz33uHn77befxuHfwRtvvKHxokWLirWO0mrAgAEa238jEf/5lG62RtKgQYM03rVrl5t3++23a5xv9YcyxbYotXEozPH/4osv0ramfNOnTx93bNup21pOYQ2GZNk6Kl27dnVjRx99dMyfefnll4v1u/JV+fLl3bGtCfTvf/877s/Z9sFPPPGExvZaLSLSpEmTuK9ha62ksx5SaXb66adr/Oc//9mN2Tbctu29iMimTZvSuzAUS3gdu+666zS2NWxERJYvX66xrS07ZcqUYv1uW6umfv36bsx+t3zrrbc0DuvYWuF6n3nmGY3TWcuPnTYAAAAAAAARxEMbAAAAAACACCI9KobLL79cY9uWNmwvPn/+/IytKdccdNBBGofbu+2WVZuSYbfdi4hs2bIlTatDqtnt3EOGDHFj06dP1/i9997L2JrwM9sqOmwRW9yUqHhsmpNNsRER6dChQ0p/V2lVtWpVdxwvFUKk+KkXxWHbtdt0u7lz57p548aNy9ia8lWy50om/z5y0X333eeOu3XrpnHdunXdmG29brfOn3rqqcX63fY1wlbe1tdff61x2HIaidl23SGb/ham8MfTvn37pH/35MmTNeZeNrZEqZ/2vnHZsmWZWA5KyKYoieyZWm399NNPGnfq1Enj/v37u3ktWrSI+fM//vijOz7ssMNixiL+Prd27dpx12StXr3aHWcqLZydNgAAAAAAABHEQxsAAAAAAIAIIj1KRI477jh3HFYp/4WtZC4iMmvWrLStKde98sorGteoUSPuvGeffVbjfOsak0t69OihcfXq1d3YmDFjNLZdGZA6Yec7y249TTe75T9cU6I13nLLLRoPHjw45euKkrCjycEHH6zxCy+8kOnlqKZNm8b873wOZl6iNIxUdC7Cz6ZNm+aOjzzySI3btGnjxk4++WSNbVeUtWvXunlPPfVUUr/bdiOZMWNG3HmTJk3SmHukogmvpzaVzaYghikYtgNmv379NA67zdhzMRy7+OKLNbbv9Zw5c5Jaez4IU2Ese7797W9/c2MjR47UmI550fHBBx+4Y5tKbb8jiIg0aNBA4/vvv1/jRKmiNt0qTMVKJF5K1O7du93xa6+9pvGVV17pxlauXJn07ysJdtoAAAAAAABEEA9tAAAAAAAAIoiHNgAAAAAAABFETRsR6d27tzsuV66cxu+//77Gn3zyScbWlItsvnDbtm3jzvvwww81DnNVUTq1bt1a4zAn9eWXX870cvLCpZdeqnGYm5stffv21fioo45yY3aN4XptTZtc9/3337tjm5Nva2qI+PpQGzZsSOk6atWq5Y7j1ReYMGFCSn8vYuvcubPG5557btx5mzZt0phWuKm1ceNGjcPW9vb4hhtuKPHvatKkica2FpiIvyZce+21Jf5d+Wrs2LHu2J47tm5NWGcmXl2N8PUuv/xyjd988003dsghh2hs62PYz+18V7NmTY3DewJb++3mm292YzfddJPGDz/8sMa2zbqIr5uycOFCjWfPnh13TS1btnTH9nsh19vEwjbcth7UAQcc4MZsbVlbd3b9+vVu3tKlSzW2fxP2O4eISMeOHYu83kcffdQd/+Uvf9HY1qvKJHbaAAAAAAAARBAPbQAAAAAAACIob9OjKlasqLFtHScismPHDo1tes7OnTvTv7AcErbytlvLbApayG793bJlS+oXhoyoU6eOxl26dNF4/vz5bp5to4fUsalImWS3NIuIHH744Rrba0AiYZvcfLr2hluIbRvfM888042NHj1a43vuuafIv6tVq1bu2KZkNGrUyI3FSwmISupdrrOfp/vsE///b3vvvfcysRykmU35CM89m34VXiuRvDCl9KyzztLYpm1XrVo17ms88MADGodpcdu2bdP41VdfdWM2/aNnz54aN23a1M3L5zbud999t8Z/+tOfkv45e338wx/+EDNOFXv+2dIOAwcOTPnvymVhupE9P4rj6aefdseJ0qNsSrr9O3vyySfdPNtSPFvYaQMAAAAAABBBPLQBAAAAAACIIB7aAAAAAAAARFDe1rS57rrrNA5bz44ZM0bjSZMmZWxNueaaa65xxx06dIg57/XXX3fHtPnODb/73e80tu2D33777SysBply4403umPb9jSRxYsXa3z++ee7MdvWMd/Y62HY+rdPnz4av/DCC0V+7XXr1rljWzvjwAMPTOo1wrxvpEe8luthLYBHHnkkE8tBig0YMMAd//a3v9XY1lwQ2bPtLVLDtuy259u5557r5tlzztYesjVsQrfddps7PuywwzQ+9dRTY76eyJ6fhfnE1jUZPny4G3v++ec1LlvWf5WtX7++xonqf6WCreFn/2Zs23ERkdtvvz2t64DI9ddfr3FRagpdeumlGhfnPiqT2GkDAAAAAAAQQTy0AQAAAAAAiKC8SY+y28hFRP76179qvHnzZjd26623ZmRNuS7ZFn1//OMf3TFtvnNDw4YNY/73jRs3ZnglSLe33npL40MPPbRYrzFnzhyNJ0yYUOI15Yp58+ZpbFvSioi0adNG42bNmhX5tW1b29BTTz3ljgcNGhRzXtiiHKlRr149dxymaPxi2bJl7njq1KlpWxPSp1evXnHH3nzzTXf8+eefp3s5ec+mStm4uMLrpE33selR3bp1c/OqV6+ucdiiPNfZFsvhda158+Zxf6579+4alytXTuNbbrnFzYtXsqG4bPpyu3btUvraiO2iiy7S2KakhSlz1uzZs93xq6++mvqFpQk7bQAAAAAAACKIhzYAAAAAAAARlNPpUTVq1ND4/vvvd2NlypTR2G7tFxGZPHlyehcGx27/FBHZuXNnkV9j06ZNcV/Dbo+sWrVq3Nc44IAD3HGy6V12C+cNN9zgxrZu3ZrUa+SiU045JeZ/HzVqVIZXkp/sVt1EHRQSbct/9NFHNa5bt27cefb1d+/enewSnb59+xbr5/LZF198ETNOha+//jqpea1atXLHs2bNSuk68tWxxx7rjuOdw2H3RZRO4XX4hx9+0Phf//pXppeDNBsxYoTGNj3q7LPPdvNs+QBKNyTn/fffj/nfbTqxiE+P+umnnzR+4okn3LzHHntM46uvvtqNxUtbRXp07NjRHdtr4/777x/352zZDdstSkRk+/btKVpd+rHTBgAAAAAAIIJ4aAMAAAAAABBBPLQBAAAAAACIoJyraWNr1YwZM0bjxo0bu3mLFi3S2Lb/RuZ9+eWXJX6Nl156yR2vXLlS49q1a2sc5gun2qpVq9zxHXfckdbfFyWdO3d2x3Xq1MnSSiAiMmzYMI3vvPPOuPNsO9lE9WiSrVWT7LyHH344qXnIDlsTKdbxL6hhkx62Jl9o3bp1Gt93332ZWA7SwNZWsPcpIiJr1qzRmBbfucd+TtrP59NOO83N+9vf/qbxiy++6MYWLFiQptXlpnfffdcd2/tz2yL64osvdvOaNWumcdeuXZP6XcuWLSvGCrE3Ye3DypUrx5xna4KJ+LpREydOTP3CMoSdNgAAAAAAABHEQxsAAAAAAIAIyrn0qKZNm2rcrl27uPNsO2ebKoXUCVuph9s+U2nAgAHF+jnb5i9RWscbb7yh8dSpU+PO+/jjj4u1jlzQr18/d2xTFadPn67xRx99lLE15bNXX31V4+uuu86N1axZM22/d+3ate547ty5Gv/+97/X2KYwInoKCwsTHiO9evbsGXds6dKlGm/atCkTy0Ea2PSo8PwaPXp03J+zKQHVqlXT2P5doPT44osvNL755pvd2F133aXxP/7xDzc2ePBgjX/88cc0rS532HsREd92/ayzzor7c926dYs7tmvXLo3tOfvnP/+5OEtEDPZ6d/311yf1M88995w7/vDDD1O5pKxhpw0AAAAAAEAE8dAGAAAAAAAggnhoAwAAAAAAEEGlvqZNw4YN3XHY0u0XYU0H2+YW6XHGGWe4Y5uLWK5cuaReo2XLlhoXpV33448/rvHixYvjznvllVc0njdvXtKvj5/tt99+Gvfu3TvuvJdfflljmwOM9FmyZInGAwcOdGOnn366xldddVVKf2/Y5v7BBx9M6esjMypUqBB3jPoJ6WE/F219vtC2bds03rlzZ1rXhOywn5ODBg1yY0OHDtV49uzZGp9//vnpXxjS6umnn3bHl1xyicbhPfWtt96q8ZdffpneheWA8HPr6quv1nj//ffXuH379m5erVq1NA6/TzzzzDMa33LLLSlYJUT8+zFnzhyNE313tOeAfW9zCTttAAAAAAAAIoiHNgAAAAAAABFU6tOjbAtZEZEGDRrEnDd+/Hh3TPvSzLvzzjtL9PPnnntuilaCVLFb8zdu3OjGbJv0++67L2Nrwp7CNuv22KaUhtfTvn37amzfz0cffdTNKygo0NhuZUXpNWTIEHf83XffaXzbbbdlejl5Yffu3RpPnTrVjbVq1UrjhQsXZmxNyI6LLrpI4wsvvNCN/e9//9OYczG3rF271h336NFD4zA154YbbtA4TKHD3q1evVpje69jW6mLiBx99NEa//3vf3dja9asSdPq8tuJJ56ocb169TRO9N3dpo3aFOJcwk4bAAAAAACACOKhDQAAAAAAQAQVFCVNqKCgIBI5RZ07d9b4rbfecmO24rTVsWNHdxxuPY66wsLCgr3P2ruovId5alphYWH7vU/bO97H7OFczAmci3sxatQod3zPPfdoPG7cuEwvJ6ZcPhfr1q3rjm+//XaNp02bpnEOdGfL23PR3svaTkAiPoV12LBhbsymIu/YsSNNqyuaXD4XoyLsjnvMMcdo3KlTJ41LkKKct+diLsmFc3HGjBkaH3HEEXHn3XXXXRrbdMEcEPNcZKcNAAAAAABABPHQBgAAAAAAIIJ4aAMAAAAAABBBpbLld5cuXTSOV8NGRGTRokUab9myJa1rAgAgV9gWqMi8FStWuOMLLrggSytBukyYMEFj2+IWiKV///7u2Nb9aNasmcYlqGkDREL16tU1Lij4tURP2GL93nvvzdiaooCdNgAAAAAAABHEQxsAAAAAAIAIKpXpUYnY7YLdu3fXeMOGDdlYDgAAAAAU2+bNm91x48aNs7QSIL3uueeemPFtt93m5q1cuTJja4oCdtoAAAAAAABEEA9tAAAAAAAAIoiHNgAAAAAAABFUUFhYmPzkgoLkJyOlCgsLC/Y+a+94D7NqWmFhYftUvBDvY/ZwLuYEzsUcwLmYEzgXcwDnYk7gXMwBnIs5Iea5yE4bAAAAAACACOKhDQAAAAAAQAQVteX3OhFZko6FIKGGKXwt3sPs4X0s/XgPcwPvY+nHe5gbeB9LP97D3MD7WPrxHuaGmO9jkWraAAAAAAAAIDNIjwIAAAAAAIggHtoAAAAAAABEEA9tAAAAAAAAIoiHNgAAAAAAABHEQxsAAAAAAIAI4qENAAAAAABABPHQBgAAAAAAIIJ4aAMAAAAAABBBPLQBAAAAAACIIB7aAAAAAAAARBAPbQAAAAAAACKIhzYAAAAAAAARxEMbAAAAAACACOKhDQAAAAAAQATx0AYAAAAAACCCeGgDAAAAAAAQQTy0AQAAAAAAiCAe2gAAAAAAAEQQD20AAAAAAAAiiIc2AAAAAAAAEcRDGwAAAAAAgAjioQ0AAAAAAEAElS3K5IKCgsJ0LQSJFRYWFqTidXgPs2pdYWFhzVS8EO9j9nAu5gTOxRzAuZgTOBdzAOdiTuBczAGcizkh5rnIThsgc5ZkewEARIRzEYgKzkUgGjgXgWiIeS7y0AYAAAAAACCCeGgDAAAAAAAQQTy0AQAAAAAAiCAe2gAAAAAAAEQQD20AAAAAAAAiiIc2AAAAAAAAEcRDGwAAAAAAgAgqm+0FAMVVs2ZNjdeuXZvFlQAAAAAAkHrstAEAAAAAAIggHtoAAAAAAABEEA9tAAAAAAAAIoiaNsi6559/3h3v2LFD4woVKsT87yIihYWFGq9cudKNvfPOOxqPGzcuJetE+vXq1csdt2nTRuPly5drPHLkSDdv06ZN6V0Y5MILL9T42GOPdWMLFy7UePjw4W7s66+/Tu/CAAAAsqhdu3Ya16pVy41NmzZN4zVr1mRsTcgt7LQBAAAAAACIIB7aAAAAAAAARBDpUUibQYMGuePnnntO4/fff1/j7t27u3mXXXaZxnYbYZ06ddy8Ll26aNy0aVM31qJFC42Lmx5VtWpVjUm/SZ/y5ctr3LJlSzdmt5uuWrVKY5sah/Tp2rWrxq1atdK4bt26bl7lypU1ttuARUiPyhR7zZs3b54bq1+/vsbffvttSn+vTWEUEdm9e7fGNWrUcGP2b2HJkiUpXQf2dM4557jj3r17azxp0iSNR4wY4eatX78+vQvLAeE1cMWKFRp37NhR4ylTpmRsTYmE52m1atU0JoU8OqpXr+6ON2zYkKWV4BeHH364xgcccIAbO+SQQzRu3bq1xqeddpqbZ+9Zt27d6sbGjx+v8RVXXFGyxSKnsdMGAAAAAAAggnhoAwAAAAAAEEGRTY+yaREie265R/TZLYUiIjfffLPGjz/+uMZNmjRx84YNGxbz9Tp37hz39Q866KBirzOeKlWqaEx6VPrUrl1bY5uSJuK7gs2ZM0fjzZs3p39heahBgwbu+IgjjtDYbvm354aIyGeffabxDz/8kKbVIRGbPtq+fXs3Nnny5LT9XtvhT0TkyCOP1DjsklGuXLm0rQM/a9SokcY2HUpE5IQTTtD4u+++07hMmTJpX1euef31192xTfmeNWuWxvbfWURkwYIFaVuTTTUWERk4cKDGhx56qBvbb7/9NCY9KrHw+4i996xYsaLGo0aNcvPCrqbx2Osi18js6Nmzp8YDBgxwYwcffLDGNv1XRGTbtm0a29Q2+3ch4r+jbNmyxY2VLRvZr+KIGHbaAAAAAAAARBAPbQAAAAAAACKIhzYAAAAAAAARFKlEuo0bN2r8xBNPuLHBgwdrPGHCBI23b9/u5tlj21I0zCO27df2339/N2bzC3/66SeNw9x9W9dh6TZH//EAABpoSURBVNKlbsz+XD7p0aOHxmF+b4cOHWKOJVufxLZ8FhHZZ59fnzmGdTQWL16c1GsmkurWuIjNtmuvV6+eG7Pv46effpqpJeUVWwOjV69ebszWsbG53GFOtm0p3b17dzdmr5vTp0/XmFamJTd06FCNbd59WEvBft6lmm33LuJbj4ft3hcuXJi2deBntu1s2ObZ1g/7/vvvNQ5rDyE2W1tx+fLlbuz000/X2P7dZ/LftmbNmu7Y1l6xNWxERL744ouMrKk0sbWdunXrpvH555/v5tn6QLNnz9bY1t0TSb6mzc6dOzVeu3ZtcotFXLZ+TKL3wNZfs/c6hx12mJtn3+/Vq1e7MXuuz5s3T+OwDqv9vhJeO+x3oE6dOmnMPe/e2RpQ9jtmWJ+xUqVKGu+7775u7MADD9TYvr+2NpmIyMyZMzW2n5+ZxE4bAAAAAACACOKhDQAAAAAAQARlPD3KbmWyWwJF/DazcCunnXvMMcdoHLZ6ti2DbavFcMuhfX27bU1E5Mcff9R43bp1Gtt2biI+BWrq1Klu7IUXXpB8NHbsWI3tljMR/x4kmxJlt7HZlnwiIgcccIDG4RbkFStWJPX6yD6bTlG3bl03NmXKlEwvJy+0bdtW4z59+mjcqlUrN89ut7fpUWGLylq1aml8yimnuLETTzxR46+++krjjz/+2M0bMWKExraNJn4VpvI2adJEY/sehGlI4XbsVLJrEPHncJiugfSz19Mw3dSmCrz33nsZW1OusOkPu3btcmOjR4/W2H5uhS2/08mmQ4mIVKtWTePwfjtM34BP1e7Xr5/Gxx57rJtnr8M2VfiEE05w8+x3iWT/vcOW0ojNprI1a9bMjdlr4KJFizS23+dE/H2MvTcJy1vYa+XWrVvdmL2mfvbZZxrb8hwi/m8BRWO/B4bnWN++fTW2aWzhPaR9722qlIj/e7HfJVu2bOnmnXzyyRqvX7/ejY0ZM0bj+fPnx/hfkRrstAEAAAAAAIggHtoAAAAAAABEEA9tAAAAAAAAIijjNW1sXu3FF1/sxh577DGNw3aw9udsnnbY1svOs3VNDjnkEDfPtnRbtmyZG7Nt+2zNnDC/zeayhjVtsGcOtc0tTcTmFffu3Vtjm2Ms4mvahLVPbH4qMiOsXxGvdWX58uXdsc0Xt3nKIr6GAIovrDtiW3u3b99eY9sCU8RfQ+01Ocy7t3XBNm7c6Mbs30W7du00DnOOZ8yYETPGrwYPHuyObW0F+7llW6uLpL5GkK1XZvPBRXwdDdrXFl9YEy6sx/CL8Nz+zW9+o3GFChXc2FtvvaXxuHHjSrrEnGevVyL+8yhsdT98+HCNM3n9atSokcb23knEX4snT57sxmj5vSf7b1mlShWNba1MEX9d2759u8a2TbiIyMEHH6xxYWGhG/v8889LtNZ8d/zxx2vcpUsXN2bv/23tkbAejX0PEr0fFStW1JjaNOlhv8+J+PtS28o7rG1qv6Pb+9XZs2e7efb7Z/i5aL/L79ixQ2N7bodrsvV5Rfw9sP2sDmvflBQ7bQAAAAAAACKIhzYAAAAAAAARlPH0KOull15yx4laI9rtTHb7dZgWY1Od7Ja27t27u3mffvqpxmFq0+rVqzW27cQ6derk5tltcmH7Wohs2rQpqXlhSoxtO2zbu4fb8G0KQJhOZ1vEhVsisSd7rogUbwtosqkQJ510kju2qYv23BPxKR+JsH01sfD6d9ppp2lst3B///33bp7d5rl06VKNN2/e7ObZrfZhu8yOHTtqbFPhqlev7ubZvwPSo2Jr06aNO7Zb+O3nmP18Swfb1t22jxfx5/DYsWPTuo5cFi8dKnTOOee4Y3ufYrdsi/iWtNi7WrVquePbbrtN4yuvvNKNJXu/kwr2XqhPnz4a22u5iMjMmTM1fu2119K/sFImTHGwaRj2nsKmFYqIzJ07V2NbrqFr165unk1dDO9z33zzTY3t9dq2HMavwvIUNr3TtmIW8Sn4NsUlvG9JFveU6ffXv/7VHdv7Cvvvb1usi/h7jE8++UTj8Du5TXsK76O+/vrrmPPCcgE21T+8dthzPdUpURY7bQAAAAAAACKIhzYAAAAAAAARlNX0qETpUCHb/cJujwq3SsXzzTffuONdu3Yl9XN2212lSpXc2IQJEzQOO1AheeF7YdMmateurXHYSchufwvTKWznKlv5P5NbmEuTTG7/DLcc7rfffhqH2/fDdKl42L66J5tSarsMiYiULfvrpd/+29lt3yJ+C/KCBQs0DjuPrFq1Ku46bGV+u73UVv0X2bPzCX42dOhQjW3ap4h/H4rTDagoaZE2VcR21QnfxzDtGaln34vDDz/cjdn3NEyTI427aMKOJrbDqU0XFfH3KgsXLkzpOmzKuIjIRRddpLE9F2fNmuXmkRKVWPPmzd2x/Zy0KRM2lUnEv/dHH320xuG9TefOnWPGIv6+16YUf/TRR27eDz/8EP9/QB6xadYiIoMGDdI47Iw2bdo0jcPSCalmU1Bt6Y50psiUVmGH2auvvlpj2/VQxJ8f9j7njTfecPOKc9+zZMkSd2zve+rUqaNx2MHRflf59ttv3Viy3ZFLip02AAAAAAAAEcRDGwAAAAAAgAjioQ0AAAAAAEAEZbWmTSYlW8NGRKRGjRoa25o2Yf4/7TNTI8zXbty4scY293D8+PFu3pgxYzROVPukQYMGGlPTJvvCNqo2d9zWiULJVK5cWWN7DoRjth7XO++84+Y9/PDDJV6HrTd1/PHHaxzWsLG1Ac466yw3NmLEiBKvo7Ro3bq1O7Z51eFnkK3VtnXr1qRe375esm2lRfz7Y9tKr1ixws0L6x0h9Wxufdh61LZ5Ds/nr776Kr0LyzHhZ5WtX3HUUUe5sbp168YcC+t92foJtvZeWOPR3of26tXLjV122WUa2xa17777rptXlLqR+cjea4qINGzYUGNbWyasM2PZ2ha2/bqIby1sP3NFROrXr6+xrYdEDZvYwnpBixcv1njOnDluLKw39YuCggJ3bK+d9jwqCvu+2ppI1LTZ0yGHHOKO7Tlg6wGJ+HsbW0/x888/L9bvtm3g7Xku4u+Pbe0pe88j4v9ewut6cddVVOy0AQAAAAAAiCAe2gAAAAAAAERQ3qRHFcVvf/tbje0W/vnz57t5xWk1hp/ZtmrnnXeeG7MtLO2Ws6lTp7p5ybaDTrYtPJJj2w4nu6XUplOEbTaXL1+ucbLb9+02dRGR3bt3J/Vz+eTggw/W+NBDD3VjhYWFGr///vsapyIdKrRmzRqNJ02apHHYwtOe92GbznxKj7LpZCIiV155pcZVqlRxY8VJdylKSpRlr9l2m7ndxiyyZytMJGa31G/ZsiWpn7HpN2HLdfv+hmkDmzdvLs4S89Z9993nju+//36Nw7Ru2862Xr16cV/TprZt3LhR4/C8sWlU/fr1c2Nly/56627bG7/33ntxfy/21LZtW3ds37dkU+nttdC27hbxKTxlypRxY/Y85R41toEDB2o8dOhQN3bNNddobM+HROx9j0jxU6Is+3dC+YXE7P2fiMiNN96ocXhPb69/lSpV0rhnz55uXoUKFTS2303CVDh73W3WrJkbs38/Nj3dpm+J+NTvsJRDohTKVGKnDQAAAAAAQATx0AYAAAAAACCCSk16lN06lSgVwm6Bslul7FYrEZHt27drHHYqsVtRbWeMp556ys1jG3jR2E4MV199tca2E4KI3zb6wQcfaFzcqvq2QwNKLtktpbbTzYABAzQO06NsFfawE008pEPtne0+YjubiPjUwtGjRyf1ejbFKkzJsJ3dwi3I1ieffKJx37593ViHDh00ttduEZEWLVpoPG/evKTWW1rZzzARn0IRbiG2qYWpFnYlsn9D9pwNuybYbmTYu2RTouyWbnuPEqZ42G58YYcLlIxNid+2bZsbs11kbJpM2CXP3nvae8gwRcamW4VdoGxa5AMPPKDx5MmTE/8PgBN2+LHXWtthJvyOYO8pbeq37RYl4j8Lw3R++xo2xQO/evHFFzUO71NsZ9kwVdFeA8Pvfsie8H2yqZ1hh2f7vjVp0kTjQYMGuXn2c9Gm1Yf3RvZ+2MYiPq3t+++/19iWDhDx19f//ve/kg3stAEAAAAAAIggHtoAAAAAAABEEA9tAAAAAAAAIqjU1LRJtobF1q1bY8ah6tWra9yyZcu482y+/siRI5NaA2Lr3r27xr/5zW80Dt/bUaNGaTxx4kSNw/xjRJttZduoUSONw1oAtnVeonooKBpbB8bm6Yr42kHJ1uayOcdh2+hk3ze7JlsDIlzjokWL3FhY4yaXha0qbR2b8N/dtqhNtpaM/Xe39TVEfL2qzp07uzHbkt22kw/rbYS56UgNez1t3LixxmENpLlz52psawag5F577bWYsYg/r2w9lLBeyfz58zW296jly5d387p166Zx2NJ46dKlGn/44YfJLB0xhDWA7OeTrcNn719EfM0iez9jWwKL+BbHBxxwgBuz19P+/ftrHLYOtnV28s3vfvc7jevUqePGbDvm8DOndu3aGtt6JWFdzJkzZ2psPwvtz4uIVKtWTePwe6U9F21dqvCzFSKzZs1yx7Zu19ixY92YrTtj3/uwBpyte2q/S4bX3eOOOy7m64n499Sew88//7yb9+6770q2sdMGAAAAAAAggnhoAwAAAAAAEEGlJj0q1Ro0aKCx3Wos4rc7jhgxQuPNmzenf2E5zG4Zttv8w21x999/v8a2bVuYNoBos9v2q1atqnGYThFuKUZq2JbNYbtR2zZ77dq1Sb3ewoULk5pn0zhERHr06KFxly5dNK5UqZKbZ8/1zz77zI19+eWXSf3uXBBu4f700081Dlu32zbpzZs319imOYn49DX7eRdu4bZ/CzaFVUSkZ8+eGtsUjzlz5sT4X4FUs9dTm94dbhefPn26xrS7zRyb3hmmASQjTLuw96hhCpydm8/pMyUVpg/af3PbZjhMj1qzZo3GNj0jTJmz6VG9evVyYzb9yqa5HnHEEW5emC6VT5588kmNL730UjdmyyWEqWcnnHCCxlWqVNE4TM3/5ptvYs5LlD5j20qL+Gus/SwcNmyYILFx48al9PXKlCmj8ZAhQ9xY+/btNbYpbSL+OvDQQw9pPGXKlJSuLxXYaQMAAAAAABBBPLQBAAAAAACIIB7aAAAAAAAARFDe1rTp06ePxmFNG5sTPn78+IytKdeErdRtTRubU2jrBon42hYW7aBLF9sy2OaHz549282L936jZGyed1gPKtX1oWxO/hlnnOHGzjzzzJjzbD65iL8m2Dad+W7JkiUaV6xY0Y01bdo0ZhzWMrGfcQceeKDGM2bMcPNsa3Wb4y/iayTZulR2fUgfW6fBtlwPr5/UGCqdbNtnEZGzzz5b47CeWHjtRGqMGjVKY9s++Nlnn3XzVq1apbGtvxbWl7Lmzp3rjj/55BON27Rpo3GnTp3cvKlTp2oc1j3KJ++99547tp9B9v0Q8febhxxyiMbh5+dRRx2lcatWrTQO6/LZ74RhbVNbg8i2sLa16EREPv/8c0F62XMnrCFl7z3DWla2tk74/SRq2GkDAAAAAAAQQTy0AQAAAAAAiKC8SY8677zz3PHgwYM1Drc0hlunUDx9+/Z1x3YLqG1BTFvS3GS3m9qWpeE24XBrK1LDtoK1KTEivnX0kUceqXGi1tp2a3Hr1q3dmN2Wetxxx7mxFi1aaGz/DlasWOHm2bSOiRMnxl1Hvpk8eXLcMXvuVK5cWeN169a5efY9sK2Jw/Rf2zKzatWqbuzEE0/U2LYlr1ChQtz1ofjq16/vju05t2vXLo1teoaIyMyZM9O7MMRk0wltS/bFixfH/RnbSvqkk05yYza9dcGCBW4sfM+RGj/99JPGI0eOTOlrh++hTbmyqf/2PllEpEePHhq/8cYbKV1TafLYY4+547Bts2XvM2xaqf0cFPGfafY9CNMR7Wewva8S8elXtWrV0rhLly5unk1pDF8Dxde2bVuNr7nmGo1PPfVUN8/eb06YMMGN2fsge28TRey0AQAAAAAAiCAe2gAAAAAAAERQTqdHNWvWTOMrrrjCjdlORo888ogbS/W2yHx16KGHumPb8cKmRDVv3tzNmzdvnsa2gr9NtxHxW1nXrFnjxsLq77/YZx//nNKmChx00EFuzG53tvGYMWNivna+C7vN2PfLpmvQ3SQzli1bpvGGDRvcmN3Ga7cP2xQbEZEGDRpoXKdOHY3Dc9umA4R/B/Z323SesLvCf//7X43pFBdbolSpRGx3hGTZ67CI/3uy74+9rofzUHzhOWZTGu2/cZjO/fXXX6d3YYhp+/btGidKibLsfZBNhxIR+eqrrzT+4IMP3Fhx0isqVarkjqOeBlAaFeXf+J133tHY3gN37NjRzQs/T/NVonSokO2yNXbsWI1t+q+IT0G13wXsdwsRn9oUfk+wnTjt65cvX97NoyNmaoT3qLY7qU3NL1vWP96w39ueeeYZN2bLdUQdO20AAAAAAAAiiIc2AAAAAAAAEcRDGwAAAAAAgAjK6Zo2Q4cO1di2BRPxeeBhftt3332X3oXliTD30+aP2jzQ7t27u3n16tXT2Ob61qxZ081buXKlxosWLXJjNifVtnTfuXOnm2dr5tj2fyIiy5cv1/iOO+6QfGLzcW2ufiLhv59teWjzecP3Culh/35tu24Rf17VqFFD427durl59pxr0qSJxvb8DX+XPd9EfH0H21rx6aefdvPCFuDIrn333dcd22unrSG2fv36jK0pn9h20CL+89PWCJsyZUqmlgQjfH+SrWNj9e7dW+Owpo2tTfTtt98W+bVDjRs3dsezZs0q8WuWdmE9LltjKKwDF0/Tpk01LleunBsL64LFY9+LsO6irV8U1n8M24hjT/Zzy143Rfw5a//dw/ul1q1ba1ytWjU3ZtuLf/zxxxqHdajsdw0UX1jzqXPnzhrbe9lJkya5eS+++KLGpamGTYidNgAAAAAAABHEQxsAAAAAAIAIyrn0qD59+mjcvn17jWfPnu3m3X333RqHLTOTZVuKhS3i8pX9N/nwww/dmN1yWLVqVY3DLaotWrTQOEyJsuz2/bC9m03vsakc4ZZ/27p2yJAhcX9Xvkk2Jcqy2xRF/HtsWw6zLTsz7Fbgzz77zI3ZVqTNmjXTOExptFvq7TXOtu4WEdm2bZvG4Vb+6dOna/z2229rTDpUtIXpFHb7uL2+2u3hSJ3atWu7Y/tZ9eWXX2r8xRdfZGxN+JVtK1wUNtWiQYMGGttrqIhPKQ6vy8lu769QoYLGfO7uKfw337VrV1I/Z+8pbWpw+HrJsu2mbeqpiL8XIx2qZOx1U8S3aN+xY4fG7dq1c/NsClzYytu2Ip85c6bGU6dOLdlioerUqaNxWIbBpql+/vnnGj/xxBNunv0OUpqx0wYAAAAAACCCeGgDAAAAAAAQQTy0AQAAAAAAiKBSX9MmbP91/vnna2zbf40cOdLNe/nll0v8u6ljsyf7bxL+G8+dO1djm6Mdts60eaa2dkZYK8PWKbLvtYivXdOwYUONw5aM1LEpGdumNDwXv/vuO43nz58f878jfZYsWaLxmDFj3NiyZcs0tq1Nu3fvHvc1bG69bUcr4tsr2ho2IiJvvvlmUZaNLLI1MMLWs/Z6a+slhfOQGh06dHDH1atX19jW1ODfPzvC2iPxhPX27GemrQdl73tEfGvh4447zo3Zz9ADDzxQ4y1btrh5ybaczlfr169Pal7lypXdsf0sLG4dG8vWR7Jtx0VExo4dW+LXx89sXTARf39Tr149jcP39Kuvvoo7Nnr0aI2pY5Me9vrXu3dvN2Zrf9m6Na+88kr6F5YFfNoDAAAAAABEEA9tAAAAAAAAIqjUp0eddNJJ7rhr164a262iudLuqzRZuHBhwuN44rUGD9sMW3bLsYhPuaIlavq0bNlS43Artt0+PmHChIytCT/buXOnxhMnTnRja9eu1dhux160aJGbZ9s+b968WePwnLIpUXPmzCnmipFtNs3UptCFY1dccUXG1pRPbIqpTVUT8WlQdsym0YjsmSKD7ArT6O19kH0fw3uYNm3aaByei507d9b42WefTck64dnzLUy/t+2hbaqo/e9FYT8z+fxMLZueGKae2TRDmyoVnrP2eNasWW7Mpg2j+Ox3PRGRo48+WuP+/ftrHKa4TZs2TWObSrhx48ZULzES2GkDAAAAAAAQQTy0AQAAAAAAiKCCcKtRwskFBclPTqN+/fppfO+997qxBg0aaGy7llxwwQVunk0PKA0KCwsL9j5r76LyHuapaYWFhe1T8UK8j9nDuZgTOBeL6Nprr9X4hx9+0HjYsGHZWI6I5N65uP/++2t81VVXxZ1nt4F/+umnaV1TBuTtuWjTnLp16+bG2rVrp/Hpp5/uxgYPHqyxTU0NUzcyKdfORdtptH79+m4s7J6YQ/L2XMwlpfFcPOuss9zxZZddprG9Fto0NhGR66+/XuO33367xOto1aqVxtm8nkqcc5GdNgAAAAAAABHEQxsAAAAAAIAI4qENAAAAAABABJXKmjbW7t273bFt05dLSmOOIvZAvnAO4FzMCZyLOYBzMSdwLuYAzsWcwLmYA3L5XHz55ZfdsW0HnmOoaQMAAAAAAFBa8NAGAAAAAAAggspmewHFYdsdhulQo0aN0rhv374ZWxMAAAAAACi5W2+9VeMcTodKCjttAAAAAAAAIoiHNgAAAAAAABHEQxsAAAAAAIAIKvUtv/NFLrdwyyO0U8wBnIs5gXMxB3Au5gTOxRzAuZgTOBdzAOdiTqDlNwAAAAAAQGnBQxsAAAAAAIAIKmrL73UisiQdC0FCDVP4WryH2cP7WPrxHuYG3sfSj/cwN/A+ln68h7mB97H04z3MDTHfxyLVtAEAAAAAAEBmkB4FAAAAAAAQQTy0AQAAAAAAiCAe2gAAAAAAAEQQD20AAAAAAAAiiIc2AAAAAAAAEcRDGwAAAAAAgAjioQ0AAAAAAEAE8dAGAAAAAAAggnhoAwAAAAAAEEH/D+VEjnGXPYv5AAAAAElFTkSuQmCC\n",
            "text/plain": [
              "<Figure size 1440x288 with 20 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          }
        }
      ],
      "source": [
        "number = 10  # how many digits we will display\n",
        "plt.figure(figsize=(20, 4))\n",
        "for index in range(number):\n",
        "    # display original\n",
        "    ax = plt.subplot(2, number, index + 1)\n",
        "    plt.imshow(x_test[index].reshape(28, 28), cmap='gray')\n",
        "    ax.get_xaxis().set_visible(False)\n",
        "    ax.get_yaxis().set_visible(False)\n",
        "\n",
        "    # display reconstruction\n",
        "    ax = plt.subplot(2, number, index + 1 + number)\n",
        "    plt.imshow(model(x_test)[index].numpy().reshape(28, 28), cmap='gray')\n",
        "    ax.get_xaxis().set_visible(False)\n",
        "    ax.get_yaxis().set_visible(False)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "id": "NG1VuO6bSlrG"
      },
      "outputs": [],
      "source": [
        ""
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    },
    "colab": {
      "name": "SparseAutoEncoder.ipynb",
      "provenance": []
    },
    "accelerator": "GPU"
  },
  "nbformat": 4,
  "nbformat_minor": 0
}